﻿using System;
#if !(NETFX_CORE)
using System.Security.Cryptography; 
#endif
using Microsoft.Xna.Framework;

namespace Syngine
{
	/// <summary>
	/// Provides access to randomly generated values.
	/// </summary>
	public static class Rand
	{
		#region Fields

		private static Random _random;

		#endregion

		#region Constructors

		static Rand()
		{
			_random = GetRandom();
		}

		#endregion

		#region Properties

		/// <summary>
		/// Gets the random.
		/// </summary>
		/// <value>
		/// The random.
		/// </value>
		public static Random Random
		{
			get
			{
				return _random;
			}
		}

		/// <summary>
		/// Gets a random opaque color.
		/// </summary>
		/// <value>
		/// The color.
		/// </value>
		public static Color Color
		{
			get
			{
				return GetColor(Random);
			}
		}

		/// <summary>
		/// Gets a random position within the current ViewPort.
		/// </summary>
		/// <value>
		/// The position.
		/// </value>
		public static Vector2 Position
		{
			get
			{
				var viewPort = GameContext.Game.GraphicsDevice.Viewport;
				return GetPosition(new Rectangle(0, 0, viewPort.Width, viewPort.Height));
			}
		}

		#endregion

		#region Methods

		/// <summary>
		/// Gets a random int.
		/// </summary>
		/// <returns></returns>
		public static int Next()
		{
			return Random.Next();
		}

		/// <summary>
		/// Gets a random int.
		/// </summary>
		/// <returns></returns>
		public static int Next(int maxValue)
		{
			return Random.Next(maxValue);
		}

		/// <summary>
		/// Gets a random int.
		/// </summary>
		/// <returns></returns>
		public static int Next(int minValue, int maxValue)
		{
			return Random.Next(minValue, maxValue);
		}

		/// <summary>
		/// Gets a random int.
		/// </summary>
		/// <returns></returns>
		public static float NextFloat()
		{
			return (float)Random.NextDouble();
		}

		/// <summary>
		/// Gets a random object.
		/// </summary>
		/// <returns></returns>
		public static Random GetRandom()
		{
#if !(NETFX_CORE || WINRT)
			var randomBytes = new byte[4];
			var rng = new RNGCryptoServiceProvider();
			rng.GetBytes(randomBytes);
			var seed = (randomBytes[0] & 0x7f) << 24 |
						randomBytes[1] << 16 |
						randomBytes[2] << 8 |
						randomBytes[3];

			return new Random(seed);
#else
			return new Random((int)Math.Ceiling((decimal)DateTime.Now.TimeOfDay.Milliseconds));
#endif
		}

		/// <summary>
		/// Gets the random position within the bounds.
		/// </summary>
		/// <param name="bounds">The bounds.</param>
		/// <returns></returns>
		public static Vector2 GetPosition(Rectangle bounds)
		{
			return new Vector2(Random.Next(bounds.X, bounds.Width), Random.Next(bounds.Y, bounds.Height));
		}

		/// <summary>
		/// Gets a random color.
		/// </summary>
		/// <returns></returns>
		public static Color GetColor()
		{
			return GetColor(Random, false);
		}

		/// <summary>
		/// Gets a random color.
		/// </summary>
		/// <returns></returns>
		public static Color GetColor(bool useTransparency)
		{
			return GetColor(Random, useTransparency);
		}

		/// <summary>
		/// Gets a random color.
		/// </summary>
		/// <param name="random">The random.</param>
		/// <returns></returns>
		public static Color GetColor(Random random)
		{
			return GetColor(random, false);
		}

		/// <summary>
		/// Gets a random color.
		/// </summary>
		/// <param name="random">The random.</param>
		/// <param name="useTransparency"></param>
		/// <returns></returns>
		public static Color GetColor(Random random, bool useTransparency)
		{
			if (useTransparency)
			{
				return new Color(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256), random.Next(0, 256));
			}

			return new Color(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256));
		}

		#endregion
	}
}